home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
-
- Arbitrary Precision Math Library General Public License
- (Written October 5, 1988)
-
- Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
- Gatos, California. Everyone is permitted to copy and distribute
- verbatim copies of this license, but changing it is not allowed.
- You can also use this wording to make the terms for other programs.
-
- The wording of this license is based on that of the
- "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
- Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
- but since some of the text has been changed, please be sure to
- READ THIS CAREFULLY!
-
- This general public license is intended to give everyone the right
- to share the Arbitrary Precision Math Library (hereinafter referred to
- as the "APM Library"). To make sure that you get the rights we want
- you to have, I need to make restrictions that forbid anyone to deny
- you these rights or to ask you to surrender the rights.
-
- Specifically, we want to make sure that you have the right to give
- away copies of the APM Library, that you receive source code or else
- can get it if you want it, that you can change the APM Library or use
- pieces of it in new programs, and that you know you can do these
- things.
-
- To make sure that everyone has such rights, we have to forbid you to
- deprive anyone else of these rights. For example, if you distribute
- copies of the APM Library, you must give the recipients all the
- rights that you have. You must make sure that they, too, receive or
- can get the source code. And you must tell them their rights.
-
- Also, for our own protection, we must make certain that everyone
- finds out that there is no warranty for the APM Library. If the APM
- Library is modified by someone else and passed on, we want its
- recipients to know that what they have is not what we distributed, so
- that any problems introduced by others will not reflect on our
- reputation.
-
- Therefore we (Lloyd Zusman and Master Byte Software) make the
- following terms which say what you must do to be allowed to
- distribute or change the APM Library.
-
- COPYING POLICIES
-
- 1. You may copy and distribute verbatim copies of the APM Library
- source code as you receive it, in any medium, provided that you
- conspicuously and appropriately publish on each copy a valid copyright
- notice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
- Gatos, California" (or with whatever year is appropriate); keep intact
- the notices on all files that refer to this License Agreement and to
- the absence of any warranty; and give any other recipients of the the
- APM Library program a copy of this License Agreement along with the
- program. You may charge a distribution fee for the physical act of
- transferring a copy.
-
- 2. You may modify your copy or copies of the APM Library source code or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish, that in
- whole or in part contains or is a derivative of the APM Library or any
- part thereof, to be licensed to all third parties on terms identical
- to those contained in this License Agreement (except that you may
- choose to grant more extensive warranty protection to some or all
- third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
- d) You may not charge a license fee for the whole of any work that
- you distribute or publish, that in whole or in part contains or is
- a derivative of the APM library or any part thereof, without the
- express written permission of Lloyd Zusman and Master Byte Software;
- whether this permission is granted for free or in return for goods
- services, royalties, or other compensation will be determined
- solely by Lloyd Zusman and Master Byte Software.
-
- Mere aggregation of another unrelated program with this program (or its
- derivative) on a volume of a storage or distribution medium does not bring
- the other program under the scope of these terms.
-
- 3. You may copy and distribute the APM Library (or a portion or
- derivative of it, under Paragraph 2) in object code or executable form
- under all the terms of Paragraphs 1 and 2 above provided that you also
- do one of the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
- For an executable file, complete source code means all the source code
- for all modules it contains; but, as a special exception, it need not
- include source code for modules which are standard libraries that
- accompany the operating system on which the executable file runs.
-
- 4. You may not copy, sublicense, distribute or transfer the APM
- Library except as expressly provided under this License Agreement.
- Any attempt otherwise to copy, sublicense, distribute or transfer the
- APM Library is void and your rights to use the APM Library under this
- License agreement shall be automatically terminated. However, parties
- who have received computer software programs from you with this
- License Agreement will not have their licenses terminated so long as
- such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of the APM Library into other
- programs whose distribution conditions are different, write to Lloyd
- Zusman at Master Byte Software. We have not yet worked out a simple
- rule that can be stated here, but we will often permit this. We will
- be guided by the goals of (1) preserving the free status of all
- derivatives of our free software; of (2) promoting the sharing and
- reuse of software; and of (3) not allowing anyone to profit from the
- use of our software without us also having the opportunity to share
- in these profits.
-
- Your comments and suggestions about our licensing policies and our
- software are welcome! Please contact Lloyd Zusman, Master Byte
- Software, 127 Wilder Ave., Los Gatos, California 95030, or call
- (408) 395-5693.
-
- NO WARRANTY
-
- BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
- ABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
- LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
- LLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE THE APM
- LIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
- SERVICING, REPAIR OR CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
- SOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
- REDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
- DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
- INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
- INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
- BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
- FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
- MASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
- THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- ******************************************************************************/
-
-
- /*
- * Multiplication and division routines for the APM library.
- *
- * $Log: muldiv.c,v $
- * Revision 1.0 88/10/05 12:38:15 ljz
- * Initial release.
- *
- */
- #ifndef lint
- static char rcsid[] = "$Header: muldiv.c,v 1.0 88/10/05 12:38:15 ljz Exp $";
- #endif /* ! lint */
-
- #include <stdio.h>
- #include "apm.h"
- #include "apmlocal.h"
-
- int
- apm_multiply(result, num1, num2)
- APM result;
- APM num1;
- APM num2;
- {
- int length1;
- int length2;
- int len;
- int dp;
- int n1;
- int n2;
- int sum;
- short sign;
- short base;
- short carry;
- long tempval;
-
- apm_errno = APM_OK;
-
- ERR_RETURN(APM_val_format(result));
- ERR_RETURN(apm_validate(num1));
- ERR_RETURN(apm_validate(num2));
-
- if (num1->base != num2->base) {
- return (APM_error(APM_EBASE));
- }
-
- if (result == num1 || result == num2) {
- return (APM_error(APM_EOVERLAP));
- }
-
- base = num1->base;
-
- sign = SIGNOF(num1->sign) * SIGNOF(num2->sign);
-
- ERR_RETURN(APM_trim(num1, 1, 1));
- ERR_RETURN(APM_trim(num2, 1, 1));
-
- length1 = num1->length;
- length2 = num2->length;
-
- len = length1 + length2;
- dp = num1->dp + num2->dp;
-
- ERR_RETURN(APM_size(result, len));
-
- APM_zero_shorts(result->data, len);
-
- for (n1 = 0; n1 < length1; ++n1) {
- carry = 0;
- sum = n1;
- for (n2 = 0; n2 < length2; ++n2, ++sum) {
- tempval = num1->data[n1];
- tempval *= num2->data[n2];
- tempval += result->data[sum] + carry;
- result->data[sum] =
- (short)(tempval % base);
- carry =
- (short)(tempval / base);
- }
- result->data[sum] = carry;
- }
-
- result->length = len;
- result->dp = dp;
- result->base = base;
- result->sign = sign;
-
- return (APM_error(APM_trim(result, 1, 1)));
- }
-
- /*
- * For division, I use the algorithm described in Knuth, "The Art of
- * Computer Programming, Volume 2, Seminumerical Algorithms", second
- * edition, pp. 255-260.
- */
- int
- apm_divide(result, frac_precision, remainder, num1, num2)
- APM result;
- int frac_precision;
- APM remainder;
- APM num1;
- APM num2;
- {
- static APM temp = (APM)NULL;
- static short *dividend = (short *)NULL;
- static int dividendLength = 0;
- static short *divisor = (short *)NULL;
- static short *xdivisor = (short *)NULL;
- static int divisorLength = 0;
-
- int i;
- int j;
- int n;
- int uJ;
- int vJ;
- int M;
- int N;
- int MplusN;
- int Nplus1;
- int MplusNplus1;
- int length1;
- int length2;
- int offset;
- int left;
- int frac;
- short divN1;
- short divN2;
- short sign;
- short base;
- short scaleFactor;
- short borrow;
- short qHat;
- long temp1;
- long temp2;
- long temp3;
-
- apm_errno = APM_OK;
-
- if (frac_precision <= 0) {
- return (APM_set_errno(APM_EPARM));
- }
-
- ERR_RETURN(APM_val_format(result));
- if (remainder != NULL) {
- ERR_RETURN(APM_val_format(remainder));
- }
- ERR_RETURN(apm_validate(num1));
- ERR_RETURN(apm_validate(num2));
-
- if (result == remainder || result == num1 || result == num2) {
- return (APM_error(APM_EOVERLAP));
- }
- if (remainder == num1 || remainder == num2) {
- return (APM_error(APM_EOVERLAP));
- }
-
- base = num1->base;
-
- ERR_RETURN(APM_trim(num2, 1, 1));
- if (num2->length <= 0) {
- /*
- * Division by zero.
- */
- result->length = 0;
- result->dp = 0;
- result->base = base;
- if (remainder != (APM)NULL) {
- remainder->length = 0;
- remainder->dp = 0;
- remainder->base = base;
- }
- return (APM_error(APM_WDIVBYZERO));
- }
-
- ERR_RETURN(APM_trim(num1, 1, 1));
- if (num1->length <= 0) {
- /*
- * Dividend is zero, so result is zero.
- */
- result->length = 0;
- result->dp = 0;
- result->base = base;
- if (remainder != (APM)NULL) {
- remainder->length = 0;
- remainder->dp = 0;
- remainder->base = base;
- }
- return (APM_OK);
- }
-
- sign = num1->sign * num2->sign;
-
- length1 = num1->length;
- length2 = num2->length;
- for (offset = length2; offset > 0; --offset) {
- if (num2->data[offset - 1] != 0) {
- break;
- }
- }
-
- offset = length2 - offset;
-
- frac = frac_precision;
- if (base == SPECIAL_BASE) {
- frac = (frac + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE;
- }
-
-
- left = (length1 - num1->dp) - (length2 - num1->dp);
- if (left < 0) {
- left = 0;
- }
-
- M = frac + left + 1;
- if (M < length1) {
- M = length1;
- }
-
- N = (length2 - offset) + 1;
- Nplus1 = N + 1;
- MplusN = M + N;
- MplusNplus1 = MplusN + 1;
-
- if (temp == (APM)NULL) {
- temp = APM_alloc();
- if (temp == (APM)NULL) {
- return (APM_error(APM_ENOMEM));
- }
- }
-
- ERR_RETURN(APM_size(temp, M + 1));
-
- if (MplusNplus1 > dividendLength) {
- int xlen = MplusNplus1;
- if (xlen < 8) {
- xlen = 8;
- }
- if (dividendLength < 1) {
- dividend = (short *)APM_alloc_mem(NULL, xlen,
- sizeof (short));
- }
- else {
- dividend = (short *)APM_alloc_mem(dividend, xlen,
- sizeof (short));
- }
- if (dividend == (short *)NULL) {
- return (APM_error(APM_ENOMEM));
- }
- dividendLength = xlen;
- }
-
- if (Nplus1 > divisorLength) {
- int xlen = Nplus1;
- if (xlen < 8) {
- xlen = 8;
- }
- if (divisorLength < 1) {
- divisor = (short *)APM_alloc_mem(NULL, xlen,
- sizeof (short));
- }
- else {
- divisor = (short *)APM_alloc_mem(divisor, xlen,
- sizeof (short));
- }
- if (divisor == (short *)NULL) {
- return (APM_error(APM_ENOMEM));
- }
- if (divisorLength < 1) {
- xdivisor = (short *)APM_alloc_mem(NULL, xlen,
- sizeof (short));
- }
- else {
- xdivisor = (short *)APM_alloc_mem(xdivisor, xlen,
- sizeof (short));
- }
- if (xdivisor == (short *)NULL) {
- return (APM_error(APM_ENOMEM));
- }
- divisorLength = xlen;
- }
-
- i = MplusN - length1;
-
- APM_zero_shorts(dividend, i);
- APM_copy_shorts(÷nd[i], num1->data, length1);
-
- divisor[0] = 0;
- APM_copy_shorts(&divisor[1], num2->data, length2 - offset);
-
- /*
- * Knuth: step D1.
- */
- scaleFactor = base / (divisor[N - 1] + 1);
- if (scaleFactor <= 1) {
- dividend[MplusN] = 0;
- }
- else {
- dividend[MplusN] = APM_scalar_mul(dividend, dividend,
- MplusN,
- scaleFactor, base);
- APM_scalar_mul(divisor, divisor, N, scaleFactor, base);
- }
-
- divN1 = divisor[N - 1];
- divN2 = divisor[N - 2];
-
- /*
- * Knuth: steps D2 and D7.
- */
- for (j = 0, vJ = M, uJ = MplusN; j <= M; ++j, --vJ, --uJ) {
- /*
- * Knuth: step D3.
- */
- temp1 = dividend[uJ];
- temp1 *= base;
- temp1 += dividend[uJ - 1];
-
- if (dividend[uJ] == divN1) {
- qHat = base - 1;
- }
- else {
- temp2 = temp1 / divN1;
- qHat = (short)temp2;
- }
-
- for (;;) {
- temp2 = divN2;
- temp2 *= qHat;
-
- temp3 = divN1;
- temp3 *= qHat;
- temp3 = temp1 - temp3;
- temp3 *= base;
- temp3 += dividend[uJ - 2];
-
- if (temp2 > temp3) {
- --qHat;
- }
- else {
- break;
- }
- }
-
- /*
- * Knuth: step D4.
- */
- xdivisor[N] = APM_scalar_mul(xdivisor, divisor, N, qHat,
- base);
- borrow = APM_array_sub(&(dividend[vJ]), xdivisor,
- Nplus1, base);
-
- /*
- * Knuth: step D5.
- */
- if (borrow == 0) {
- temp->data[vJ] = qHat;
- }
- else {
- /*
- * Knuth: step D6.
- */
- temp->data[vJ] = qHat - 1;
- divisor[N] = 0;
- APM_array_add(&(dividend[vJ]), divisor, Nplus1, base);
- }
- }
-
- /*
- * Knuth: step D8.
- */
- temp->length = M + 1;
- temp->dp = (M - offset) -
- ((length1 - num1->dp) - (length2 - num2->dp));
- temp->base = base;
- temp->sign = sign;
-
- ERR_RETURN(apm_round(result, temp, frac_precision));
- ERR_RETURN(APM_trim(result, 1, 1));
-
- if (remainder != (APM)NULL) {
- ERR_RETURN(APM_size(temp, length2));
- if (scaleFactor > 1) {
- ERR_RETURN(APM_scalar_div(temp, ÷nd[1],
- length2,
- num2->dp,
- num2->sign,
- base, scaleFactor));
- }
- else {
- temp->length = length2;
- temp->dp = num2->dp;
- temp->sign = num2->sign;
- temp->base = base;
- APM_copy_shorts(temp->data, ÷nd[1], length2);
- }
- ERR_RETURN(apm_round(remainder, temp, frac_precision));
- ERR_RETURN(APM_trim(remainder, 1, 1));
- }
-
- return (APM_OK);
- }
-